import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.parosproxy.paros.network.HttpHeader;
import org.parosproxy.paros.network.HttpMalformedHeaderException;

import com.totalvalidator.parser.CommandLineParser;
import com.totalvalidator.parser.TagParser;
import com.totalvalidator.sgml.EntityEncoder;
import com.totalvalidator.sgml.RealAttribute;
import com.totalvalidator.sgml.Tag;
import com.totalvalidator.utils.FileUtils;
import com.totalvalidator.utils.MyReader;

public class AccelaPlayListener implements PlayListener {

	public AccelaPlayListener() {
		init();
	}

	private void init() {
		//read replace config
		String replaceFile = "play\\replace.txt";
		Hashtable replaceHash = Util.getHashdata(replaceFile);
		PlayData.getReplaceData().putAll(replaceHash);

		//read session data
		String sessionFile = "play\\session.txt";
		Hashtable session = Util.getHashdata(sessionFile);
		PlayData.addSessionData(session);
		
		//read skip data
		String skipFile = "play\\skips.txt";
		List skip = Util.getListdata(skipFile);
		PlayData.addSkipData(skip);
	}

	public boolean afterPlay(Record msg, Hashtable records) {
		//handle cookie
		try {
			Vector cookies = msg.getHttpMessage().getResponseHeader()
					.getHeaders("Set-Cookie");
			if (cookies != null) {
				for (int i = 0; i < cookies.size(); i++) {
					String cookie = (String) cookies.get(i);
					Hashtable cookieHash = new Hashtable();
					StringTokenizer tokens = new StringTokenizer(cookie, ";");
					while (tokens.hasMoreTokens()) {
						String token = tokens.nextToken().trim();
						String key = token;
						String value = "";
						int pos = token.indexOf("=");
						if (pos > -1) {
							try {
								key = token.substring(0, pos);
								value = token.substring(pos + 1);
							} catch (Exception me) {

							}
						}
						PlayData.addCookieData(key, value);
					}
				}
			}
		} catch (Exception me) {
			me.printStackTrace();
		}
		
		//fetch response data
		try{
			String extractFile = "play\\"+msg.getId()+"_extract.txt";
			List<String> extracts = Util.getListdata(extractFile);
			if(extracts!=null && extracts.size()>0){				
				String response = msg.getHttpMessage().getResponseBody().toString();
				if(response!=null && response.length()>0){
					CommandLineParser commandlineparser = new CommandLineParser();
					TagParser  tagparser = new TagParser();
					FileUtils fileUtils = new FileUtils();
					EntityEncoder   defaultEncoder = new EntityEncoder();
					MyReader reader = new MyReader(); 
					java.io.ByteArrayInputStream in = new java.io.ByteArrayInputStream(response.getBytes());
					reader.setInputStream(in);
					List tags = tagparser.parseFile(reader, false, null, false, fileUtils, commandlineparser, defaultEncoder);
					for(String extract:extracts){
						fetchData(tags,extract);
					}
				}
			}
		}catch(Exception me){
			me.printStackTrace();
		}
		
		//verify response data
		try{
			String verifyFile = "play\\"+msg.getId()+"_verify.txt";
			List<String> verifyList = Util.getListdata(verifyFile);
			if(verifyList!=null && verifyList.size()>0){
				String response = msg.getHttpMessage().getResponseBody().toString();
				if(response!=null && response.length()>0){
					for(String verifyStr:verifyList){
						if(response.indexOf(verifyStr)==-1){
							System.out.println("can't find "+verifyStr+" in response data");
						}
					}
				}
			}
			
		}catch(Exception me){
			me.printStackTrace();
		}
		return true;
	}
	
	public void fetchData(List tags,String extractor){
		String className = "";
		java.util.StringTokenizer tokens = new java.util.StringTokenizer(extractor,";=");
		while(tokens.hasMoreElements()){
			String token = tokens.nextToken();
			if(token.equalsIgnoreCase("classname")){
				className = tokens.nextToken();
				break;
			}
		}
		
		try {
			Object obj = Class.forName(className).newInstance();
			if(Extractor.class.isInstance(obj)){
				((Extractor) obj).extract(tags, extractor);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}		

		
	}

	public boolean beforePlay(Record msg, Hashtable records) {

		
		String id = msg.getId();
		String skipsFile = "play\\"+id+"_skips.txt";
		String setFile = "play\\"+id + "_set.txt";
		String replaceFile = "play\\"+id+"_replace.txt";
		
		List skipsList= Util.getListdata(skipsFile);
		skipsList.addAll(PlayData.getSkipData());
		
		Hashtable setHash = Util.getHashdata(setFile);
		setHash.putAll(PlayData.getSessionData());
		
		Hashtable replaceHash = Util.getHashdata(replaceFile);
		replaceHash.putAll(PlayData.getReplaceData());
		
		
		//handle replace first
		try {
			String header = msg.getHttpMessage().getRequestHeader().toString();
			String body = msg.getHttpMessage().getRequestBody().toString();
			Enumeration en = replaceHash.keys();
			while (en.hasMoreElements()) {
				String key = (String) en.nextElement();
				String value = (String)replaceHash.get(key);
				if (header != null && header.length() > 0) {
					header = header.replace(key, value);
				}
				if (body != null && body.length() > 0) {
					key = URLEncoder.encode(key,"UTF-8");
					value = URLEncoder.encode(value,"UTF-8");
					body = body.replace(key, value);
				}
			}

			msg.getHttpMessage().getRequestHeader().setMessage(header);
			if (body != null && body.length() > 0) {
				msg.getHttpMessage().getRequestBody().setBody(body);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		//handle request get params
		try {
			String queryStr = msg.getHttpMessage().getRequestHeader().getURI()
					.getQuery();
			if (queryStr != null && queryStr.length() > 0) {
				Hashtable queryHash = new Hashtable();
				StringTokenizer tokens = new StringTokenizer(queryStr, "&");
				while (tokens.hasMoreTokens()) {
					String token = tokens.nextToken();
					int pos = token.indexOf("=");
					String key = token;
					String value = "";
					try {
						key = URLDecoder.decode(token.substring(0, pos),
								"UTF-8");
						value = URLDecoder.decode(token.substring(pos + 1),
								"UTF-8");

					} catch (Exception me) {

					}

					if(setHash.containsKey(key)){
						value = (String)setHash.get(key);
					}
					queryHash.put(key, value);
				}
				queryStr = Util.getRequestParasAsString(queryHash,false);
				msg.getHttpMessage().getRequestHeader().getURI().setQuery(
						queryStr);
			}
		} catch (Exception me) {
			me.printStackTrace();
		}

		//handle request post params
		try {
			String postStr = msg.getHttpMessage().getRequestBody().toString();
			if (postStr != null && postStr.length() > 0) {
				Hashtable postHash = new Hashtable();
				Pattern pSeparator = Pattern.compile("([^=&]+)[=]([^=&]*)");
				String name = null;
				String value = null;
				StringBuffer buffer = new StringBuffer();
				Matcher matcher = pSeparator.matcher(postStr);
				while (matcher.find()) {
					try {
						boolean skip = false;
						name = URLDecoder.decode(matcher.group(1), "8859_1");
						value = URLDecoder.decode(matcher.group(2), "8859_1");
						if(setHash.containsKey(name)){
							value = (String)setHash.get(name);
						}else{						
							//check skip?
							for(int i=0; i< skipsList.size(); i++){
								if(name.equals(skipsList.get(i))){
									skip = true;
									break;
								}
							}
						}
						if(!skip){
							postHash.put(name, value);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				postStr = Util.getRequestParasAsString(postHash,true);
				msg.getHttpMessage().getRequestBody().setBody(postStr);
			}
		} catch (Exception me) {
			me.printStackTrace();
		}

		//handle cookie
		try {
			String cookies = msg.getHttpMessage().getRequestHeader().getHeader(
					"Cookie");
			if (cookies != null && cookies.length() > 0) {
				Hashtable cookieHash = new Hashtable();
				StringTokenizer tokens = new StringTokenizer(cookies, ";");
				while (tokens.hasMoreTokens()) {
					String token = tokens.nextToken().trim();
					int pos = token.indexOf("=");
					String key = token;
					String value = "";
					try {
						key = token.substring(0, pos);
						value = token.substring(pos + 1);
					} catch (Exception me) {

					}
					if(PlayData.isCookieData(key)){
						value = PlayData.getCookieData(key);
					}
					cookieHash.put(key, value);
				}
				cookies = Util.getCookieAsString(cookieHash);
				msg.getHttpMessage().getRequestHeader().setHeader("Cookie",
						cookies);
			}
		} catch (Exception me) {
			me.printStackTrace();
		}

		msg.getHttpMessage().getRequestHeader().setContentLength(
				msg.getHttpMessage().getRequestBody().length());

		return true;
	}

}
